using System;
using System.Collections.Specialized;
using System.IO;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Rhino.Mocks;

namespace Azure.Tests
{
    public class ControllerFacts<TController> : Facts<TController> where TController : Controller
    {
        private static readonly object RouteLockObject = new object();

        public ControllerFacts()
        {
            InitializeController();
        }

        public ControllerFacts(Action<RouteCollection> routeRegistrar) : this()
        {
            lock (RouteLockObject)
            {
                if (RouteTable.Routes.Count > 0)
                {
                    RouteTable.Routes.Clear();
                }

                routeRegistrar(RouteTable.Routes);
            }
        }

        private void InitializeController()
        {
            ResponseString = new StringBuilder();
            Response = Mock<HttpResponseBase>();
            Request = Mock<HttpRequestBase>();
            HttpContext = Mock<HttpContextBase>();

            Request.Stub(p => p.Files).Return(Mock<HttpFileCollectionBase>());
            Request.Stub(p => p.QueryString).Return(new NameValueCollection());
            Request.Stub(p => p.Cookies).Return(new HttpCookieCollection());
            Request.Stub(p => p.Form).Return(new NameValueCollection());
            Request.Stub(p => p.Headers).Return(new NameValueCollection());
            Request.Stub(p => p.ContentType).PropertyBehavior();
            Request.Stub(p => p.ContentEncoding).PropertyBehavior();

            Response.Stub(p => p.ContentType).PropertyBehavior();
            Response.Stub(p => p.Buffer).PropertyBehavior();
            Response.Stub(p => p.BufferOutput).PropertyBehavior();
            Response.Stub(p => p.CacheControl).PropertyBehavior();
            Response.Stub(p => p.Charset).PropertyBehavior();
            Response.Stub(p => p.ContentEncoding).PropertyBehavior();
            Response.Stub(p => p.Expires).PropertyBehavior();
            Response.Stub(p => p.ExpiresAbsolute).PropertyBehavior();
            Response.Stub(p => p.Filter).PropertyBehavior();
            Response.Stub(p => p.HeaderEncoding).PropertyBehavior();
            Response.Stub(p => p.RedirectLocation).PropertyBehavior();
            Response.Stub(p => p.Status).PropertyBehavior();
            Response.Stub(p => p.StatusCode).PropertyBehavior();
            Response.Stub(p => p.StatusDescription).PropertyBehavior();
            Response.Stub(p => p.SubStatusCode).PropertyBehavior();
            Response.Stub(p => p.SuppressContent).PropertyBehavior();
            Response.Stub(p => p.TrySkipIisCustomErrors).PropertyBehavior();
            Response.Stub(p => p.Cache).Return(Mock<HttpCachePolicyBase>());
            Response.Stub(p => p.Headers).Return(new NameValueCollection());
            Response.Stub(p => p.Cookies).Return(new HttpCookieCollection());
            Response.Stub(p => p.Output).Return(new StringWriter(ResponseString));
            Response.Stub(x => x.ApplyAppPathModifier(Arg<string>.Is.Anything))
                .Return("")
                .WhenCalled(m => m.ReturnValue = m.Arguments[0]);
            Response.Stub(x => x.Write(null))
                .IgnoreArguments()
                .WhenCalled(m => ResponseString.Append(m.Arguments[0]));

            HttpContext.Stub(p => p.Request).Return(Request);
            HttpContext.Stub(p => p.Response).Return(Response);
            HttpContext.Stub(p => p.Server).Return(Mock<HttpServerUtilityBase>());

            RequestContext = new RequestContext(HttpContext, new RouteData());
            ClassUnderTest.ControllerContext = new ControllerContext(RequestContext, ClassUnderTest);
            ClassUnderTest.Url = new UrlHelper(RequestContext);
        }

        public StringBuilder ResponseString { get; private set; }
        public RequestContext RequestContext { get; private set; }
        public HttpResponseBase Response { get; private set; }
        public HttpRequestBase Request { get; private set; }
        public HttpContextBase HttpContext { get; private set; }
    }
}